#include "wifi_connect.hpp"
#include <string.h>
#include <stdlib.h>
#include "stimer.h"
#include "bsp_uart.h"
#include "servo.h"
#include "smartlock.h"

// only debug
#define debug_printf(fmt, ...) UARTx_Printf(&huart1, fmt, ##__VA_ARGS__)
#define debug_printn(data, n) UARTx_Printn(&huart1, data, n)

extern class SmartLock smartlock;
AT_AiCombo::mqtt_topic_t user_mqtt_topics[] =
{
    {
        "SharpIot/V0/Mode0/Float", // topic string
        2,                         // id
        0,                         // qos
        false,                     // retained
    },
    {
        "SharpIot/V0/Mode0/Int",
        3,
        0,
        false,
    },
    {
        "SharpIot/V0/Mode0/Bool",
        4,
        0,
        false,
    },
};
extern "C" __weak void user_subscribe_callback(uint16_t id, const uint8_t *pPayload, uint16_t len)
{

}
AT_AiCombo::mqtt_cfg_t user_mqtt_cfg =
{
    "104.208.69.92",        // 服务器地址
    "1883",                 // 服务器端口
    "a40fd3852",            // 客户端ID
    "f4264da92",            // 用户名
    "a05bb481f999b031",     // 密码
    &user_mqtt_topics[0],   // 订阅的主题
    sizeof(user_mqtt_topics)/sizeof(user_mqtt_topics[0]),// 主题数量
    user_subscribe_callback // 订阅消息回调
};

wifiConnect::wifiConnect(AT_AiCombo *wifiModule)
{
    wifi = wifiModule;
    
    ap_ssid = NULL;
    ap_pwd = NULL;
    ap_ssid = NULL;
    state = STATE_IDLE;
    timeout = 60 * 1E3;
}

int wifiConnect::setAP(const char *ssid, const char *pwd)
{
    if (ssid == NULL || pwd == NULL)
    {
        return -1;
    }
    size_t ssid_len = strlen(ssid);
    size_t pwd_len = strlen(pwd);
    if (ssid_len > 32 || pwd_len > 32)
    {
        debug_printf("[wifiConnect] ssid or password too long\n\r");
    }
    memcpy(this->wifi->ap_info.ssid, ssid, strlen(ssid)+1);
    memcpy(this->wifi->ap_info.pwd, pwd, strlen(pwd)+1);
    this->wifi->ap_info.bssid[0] = '\0';
    this->ap_ssid = this->wifi->ap_info.ssid;
    this->ap_pwd = this->wifi->ap_info.pwd;
    this->ap_bssid = NULL;
    return 0;
}
int wifiConnect::setAP(const char *ssid, const char *pwd, const char *bssid)
{
    if (ssid == NULL || pwd == NULL || bssid == NULL)
    {
        return -1;
    }
    size_t ssid_len = strlen(ssid);
    size_t pwd_len = strlen(pwd);
    size_t bssid_len = strlen(bssid);
    if (ssid_len > 32 || pwd_len > 32 || bssid_len > 17)
    {
        debug_printf("[wifiConnect] ssid or password or bssid too long\n\r");
    }
    memcpy(this->wifi->ap_info.ssid, ssid, ssid_len+1);
    memcpy(this->wifi->ap_info.pwd, pwd, pwd_len+1);
    memcpy(this->wifi->ap_info.bssid, bssid, bssid_len+1);
    this->ap_ssid = this->wifi->ap_info.ssid;
    this->ap_pwd = this->wifi->ap_info.pwd;
    this->ap_bssid = this->wifi->ap_info.bssid;
    return 0;
}

void wifiConnect::setTimeout(uint32_t time)
{
    timeout = time;
}

void wifiConnect::start_connect(void)
{
    this->time = 0;
    this->sleep_time = 0;
    this->sub_state = 0;
    this->sub_state_shadow = 0;
    this->state = STATE_INIT;
//    this->wifi->reset();
    sleep(500, 0);
}

void wifiConnect::start_connect(const char *ssid, const char *password)
{
    setAP(ssid, password);
    start_connect();
}

void wifiConnect::start_connect(const char *ssid, const char *password, const char *bssid)
{
    setAP(ssid, password, bssid);
    start_connect();
}

void wifiConnect::stop_connect(void)
{
    this->state = STATE_STOP;
    awake(0);
}

bool wifiConnect::get_state(void)
{
    return this->state == STATE_CPLT;
}

void wifiConnect::run_connect(void)
{
    // time++;
    switch (this->state)
    {
    case STATE_INIT: // 尝试连接WIFI
        if (sub_state == 0)
        {
            if (this->wifi->get_cmd_num() == 0)
            {
                sleep(1, 1);
            }
            else
            {
                sleep(1,0);
            }
        }
        if (sub_state == 1)
        { 
            // 切换为STA模式,开启自动连接
            debug_printf("[wifiConnect] try connect Wifi:%s,%s\n\r", ap_ssid, ap_pwd);
            wifi->set_wmode(AT_AiCombo::WMODE_STATION);
            wifi->join_ap(ap_ssid, ap_pwd, ap_bssid);
            sleep(1000, 2);
        }
        else if (sub_state == 2)
        {
            if (wifi->get_network_state())
            {
                // 切换为STA模式成功
                debug_printf("[wifiConnect] connect %s OK\n\r", ap_ssid);
                this->state = STATE_TRY_CONNECT;
                sleep(1, 0);
            }
            else if (wifi->get_cmd()->__state == ATBase::CMD_STATE_FAILED)
            {
                if (timeout < time)
                {
                    stop_connect();
                    break;
                }
                wifi->clear(); // 清除命令
                sleep(1, 0);
            }
            else sleep(1);
        }
        break;
    case STATE_TRY_CONNECT: // 连接MQTT服务器
        if (sub_state == 0)
        {
            debug_printf("mqttConnect] Mqtt User Config...\n\r");
            this->wifi->mqtt_connect(&user_mqtt_cfg);
            sleep(1, 1);
        }
        else if (sub_state == 1)
        {
            // 连接云平台服务器
            if (this->wifi->mqtt_state)
            {
                debug_printf("[mqttConnect] IoT Mqtt Connect OK\n\r");
							  this->state = STATE_TRY_SUBSCRIBE;
                sleep(1, 0);
            }
            else if (this->wifi->get_cmd()->__state == ATBase::CMD_STATE_FAILED)
            {
                debug_printf("[mqttConnect] IoT Mqtt Connect Failed\n\r");
                this->wifi->clear();
                sleep(1, 0); // 重新连接
            }
            else sleep(1);
        }
        break;
    case STATE_TRY_SUBSCRIBE:
        if (this->sub_state == 0)
        {
            debug_printf("[mqttConnect] IoT Mqtt subscribe start\n\r");
            this->wifi->mqtt_subscribe();
            sleep(1, 1);
        }
        else if (this->sub_state == 1)
        {
            if (this->wifi->get_cmd_num() == 0)
            {
                debug_printf("[mqttConnect] IoT Mqtt Subscribe OK\n\r");
                this->state = STATE_CPLT;
                sleep(1, 0);
                smartlock.setLedState(3);// 已连接服务器，短闪
            }
            else if (this->wifi->get_cmd()->__state == ATBase::CMD_STATE_FAILED)
            {
                debug_printf("[mqttConnect] IoT Mqtt Subscribe Failed,num:%d\n\r", this->wifi->get_cmd_num());
                this->wifi->clear();
                sleep(1, 0); // 重新订阅
            }
            else sleep(1);
        }
        break;
    case STATE_CPLT: // 完成连接

        break;
    case STATE_STOP:
        // TODO:
        this->wifi->reset();
        state = STATE_IDLE;
        time = 0;
        break;
    default:
        break;
    }

    if (time > timeout)
    {
        stop_connect();
        debug_printf("[wifi] Connect timeout,stop connect\n\r");
        return;
    }
}

void wifiConnect::wake_task(const void *arg)
{
    wifiConnect *wifiCfg = (wifiConnect *)arg;
    wifiCfg->time += wifiCfg->sleep_time;
    wifiCfg->sleep_time = 0;
    if (wifiCfg->sub_state_shadow != 0xFF)
    {
        wifiCfg->sub_state = wifiCfg->sub_state_shadow;
    }
    wifiCfg->sub_state_shadow = 0;
    //debug_printf("wake up wifi connect task\n\r");
    wifiCfg->run_connect();
}

/**
 * @brief 休眠一段时间
 * @param ms 时间
 * @param subState 休眠后更新子状态的值[0,255)
 * @retval true 休眠成功
 * @retval false 当前休眠未结束
 */
bool wifiConnect::sleep(uint32_t ms, uint8_t subState)
{
    if (sleep_time != 0)
    {
        return 0; // 当前休眠未结束
    }
    if (ms == 0)
        ms = 1;
    sleep_time = ms; // 开启休眠
    sub_state_shadow = subState;
    stimer_task_oneshot(wake_task, sleep_time, 1, this);
    return 1;
}

bool wifiConnect::sleep(uint32_t ms)
{
    return sleep(ms, 0xFF); // 0xFF用做不更新子状态设置的标志
}

bool wifiConnect::awake(void)
{
    // debug_printf("currnt state:%d,next:%d\n\r", state, sub_state);
    sleep_time = 0;
    return sleep(1);
}

bool wifiConnect::awake(uint8_t substate)
{
    // debug_printf("currnt state:%d,next:%d\n\r", state, substate);
    sleep_time = 0;
    return sleep(1, substate);
}


